import 'package:dart_learn/ui_demo.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

// dart基础语法
void main() {
  // listTest();
  // mapTest();
  // stringTest();
  // numTest();
  // test1();
  // test2();

  /*
    // Dart 方法的可选参数 这里方法调用的时候参数可选，但是可选参数必须带上形参的名称
  print(sum(20));
  print(sum(20, b: 10));
  // 这里可以不用按照方法中的顺序传参
  print(sum(20, c:5, b:10));
  // 用 [] 修饰可选参数调用的时候可以不用带参数名称，但是必须按参数的顺序传值
  print(sum3(20, 5, 10));
   */

  /*
  Dart 方法作为参数传递
    var hello = helloDemo;
  hello();

  var list = [1, 2, 3, 4];
  // list.forEach(print);
  forEachDemo(list, printElement);
   */

  /*
    // Dart 中的匿名函数这里 () {} 部分属于匿名函数，但是需要用一个变量接收，才能被调用，匿名方法也可以作为参数传递
  var func = () {
    print('匿名方法');
  };
  func();

  // 以 (() {}) () 这种形式实现的匿名函数会立即执行，属于立即执行函数
  (() {
    print('立即执行函数');
  })();
   */
  //对于不变的控件用 const 修饰
  runApp(const MyApp());
}

helloDemo() => print('hello');

forEachDemo(List list, void func(var element)) {
  for (var e in list) func(e);
}

int b = 0;
printElement(var a) {
  b++;
  print('元素$b = $a');
}

test3() {
  var a;
  // 如果 a 没有值，就进行赋值，如果 a 有值就不会赋值
  a ??= 10;

  var b;
  // 如果左边有值就打印左边，如果左边没值就打印右边
  print(a ?? b);

  // 正常写法
  int sum(int a, int b) {
    return a + b;
  }

// 省略参数跟返回值
  sum1(a, b) {
    return a + b;
  }

// 使用箭头函数 => 表达式
  sum2(a, b) => a + b;
}

mapTest() {
  // 不可变 map
  var map1 = const {'key1': 'one', 'key2': 'two'};

  // 可变 map
  var map2 = {'key1': 'one', 'key2': 'two'};
  // 获取 key 对应的值
  print(map2['key1']);
  // 修改 key 对应的值
  map2['key1'] = 'hello';
  // 打印 map 的长度
  print(map2.length);
  // 获取 map 中所有的 value
  print(map2.values);
  // 获取 map 中所有的 key
  print(map2.keys);

  // 将 list 转为 map，结果就是 {0: one, 1: two, 2: three}
  var list = ['one', 'two', 'three'];
  var map3 = list.asMap();
}

listTest() {
  // 不可变 list，数据先去加 const 修饰
  var list = const ['one', 'two', 'three', 1];

  // 可变 list
  var list1 = ['one', 'two', 'three', 1];
  // 根据下标打印元素
  print(list1[1]);
  // 修改下标为 1 的元素
  list1[1] = 3;
  // 打印 list 元素数量
  print(list1.length);
  // 追加一个元素
  list1.add(5);
  // 在 下边为 1 的位置插入一个元素
  list1.insert(1, '33');
  // 删除某个元素
  list1.remove('one');
  // 清空 list
  list1.clear();

  var list2 = [1, 3, 2];
  // 对 list 进行排序，得到的结果就是 [1, 2, 3]
  list2.sort();
  // 获取 list 下标 1 到 3 之间的元素
  list2.sublist(1, 3);
  // 取数组前2个,不够2个有几个取几个
  list2.take(2);
}

stringTest() {
  // 用单引号或者双引号修饰都可以
  var a = 'hello';
  var b = "world";
  String c = a + b;

  // 用 3 个引号修饰，字符串可以换行
  String d = '''hello
  world''';

  // 获取字符串 a 中的第 0 个字符跟第 1 个字符，这里可以看到会非常方法，可以用下标的方式去取
  print(a[0]);
  print(a[1]);

  String e = a * 2; // 这个结果等于 hellohello，就是把 a 的值再复制一份

  int f = 10;
  int g = 20;
  int h = f + g;
  print('a + b = ${a + b}'); // 输出结果为 a + b = 30，在字符串里面拼接运算表达式
  print('a + b = $h'); // 这个结果跟上面输出结果是一样的

  String str = "hello\nworld";
  print(str); // 这个输出的结果就是 hello 换行之后是 world

  String str1 = r"hello\nworld";
  print(str1); // 这个输出的结果就是 hello\nworld, \n 没起作用

  print(str1.length); // 打印字符串长度
}

numTest() {
  /*
    Dart 的数据类型之 num
数值型 num 分为两种 int 跟 double。
num 类型的变量如果被使用的话必须要有值，
   */
  int a = 10;
  print(a.isEven); // 判断是否是偶数
  print(a.isOdd); // 判断是否是奇数

  // 运算符 + - * / % (取模)  ~/ (取整数)
  int b = a + 10;
  int c = a - 5;
  int d = a * 3;
  double e = a / 2;
  int f = a % 6;
  int g = a ~/ 8; // 这个结果为 1，相当于 a 除 8 的结果取整

  // 转换类型
  int h = 10.3.toInt(); // double 类型转换为 int
  double i = 5.toDouble(); // int 类型转换为 double
}

test2() {
  /*
  使用 final 声明的变量只能被赋值一次，再次赋值的话会报错，它是最终变量。
  使用 final 声明的变量在使用前必须有值，不然也会报错。
   */
  final int c;
  // jdLog(c);
  c = 1;
/*
   const 关键字
     使用 const 声明的常量初始化的时候必须被赋值。
  使用 const 声明的常量不能被修改。
 */
  const d = 10;
}

test1() {
  String testString = 'testString';
  var a = '1';
  jdLog('$a $testString');
  a = 'hello world';
  jdLog(a);

  int b = 10;
  jdLog(b);
}

sum(a, {b, c}) {
  b ??= 0;
  c ??= 0;
  return a - b + c;
}

// 参数如果为 int 型，就需要用 int？修饰，告诉编译器参数可以为空
sum1(a, {int? b, int? c}) {
  b ??= 0;
  c ??= 0;
  return a - b + c;
}

// 也可以给参数一个默认值
sum2(a, {int b = 0, int c = 0}) {
  return a - b + c;
}

// 用 [] 修饰可选参数调用的时候可以不用带参数名称，但是必须按参数的顺序传值
sum3(a, [int b = 0, int c = 0]) {
  return a - b + c;
}

void jdLog(
  Object log,
) {
  if (kDebugMode) {
    print("$log");
  }
}
